package logger

import (
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	_ "github.com/gookit/color" // 用于level.go中的颜色支持
)

// ILogger 日志接口
type ILogger interface {
	// 基础日志方法
	Trace(args ...interface{}) // 跟踪日志
	Debug(args ...interface{}) // 调试日志
	Info(args ...interface{})  // 信息日志
	Warn(args ...interface{})  // 警告日志
	Error(args ...interface{}) // 错误日志
	Fatal(args ...interface{}) // 致命错误日志
	Panic(args ...interface{}) // 恐慌日志

	// 结构化日志方法
	TraceWithFields(msg string, fields Fields) // 带字段的跟踪日志
	DebugWithFields(msg string, fields Fields) // 带字段的调试日志
	InfoWithFields(msg string, fields Fields)  // 带字段的信息日志
	WarnWithFields(msg string, fields Fields)  // 带字段的警告日志
	ErrorWithFields(msg string, fields Fields) // 带字段的错误日志

	// 管理方法
	Close() error // 关闭日志器
}

// Field 结构化字段（单个键值）
// 用于以 key=value 的形式输出结构化日志字段
// 例如：logger.Info("登录", Field{Key: "user", Value: 123})
type Field struct {
	Key   string      // 键
	Value interface{} // 值
}

// Fields 结构化字段集合
// 可一次性传入多个键值对，例如：logger.Info("登录", Fields{"user":123, "ok":true})
type Fields map[string]interface{}

// Config 日志配置
// Config 定义了日志的输出、级别、是否包含源码信息等参数
// 新增：
// - SampleEvery：采样间隔（>1 表示每间隔N条仅记录1条）
// - Async：是否启用异步写入
// - AsyncBuffer：异步队列的缓冲大小
// - DefaultFields：默认结构化字段（所有日志都带上）
type Config struct {
	Prefix        string // 日志前缀
	MaxSize       int64  // 日志文件最大大小（字节）
	MaxDays       int    // 日志文件最大保存天数
	Level         Level  // 日志级别
	Output        string // 日志文件夹路径
	EnableConsole bool   // 是否启用控制台输出
	EnableSource  bool   // 是否输出源代码文件名和行号

	// ---------- 新增功能配置 ----------
	SampleEvery   int    // 日志采样间隔，>1 表示每间隔N条记录1条
	Async         bool   // 是否启用异步写入
	AsyncBuffer   int    // 异步队列缓冲大小
	DefaultFields Fields // 默认结构化字段
}

// Validate 验证配置的有效性
func (c *Config) Validate() error {
	// 验证文件大小
	if c.MaxSize <= 0 {
		return fmt.Errorf("MaxSize 必须大于 0，当前值: %d", c.MaxSize)
	}

	// 验证保存天数
	if c.MaxDays <= 0 {
		return fmt.Errorf("MaxDays 必须大于 0，当前值: %d", c.MaxDays)
	}

	// 验证日志级别
	if c.Level < TraceLevel || c.Level > PanicLevel {
		return fmt.Errorf("无效的日志级别: %d", c.Level)
	}

	// 验证输出路径
	if c.Output == "" {
		return fmt.Errorf("Output 路径不能为空")
	}

	// 验证异步配置
	if c.Async && c.AsyncBuffer <= 0 {
		return fmt.Errorf("启用异步时 AsyncBuffer 必须大于 0，当前值: %d", c.AsyncBuffer)
	}

	// 验证采样配置
	if c.SampleEvery < 0 {
		return fmt.Errorf("SampleEvery 不能为负数，当前值: %d", c.SampleEvery)
	}

	return nil
}

// SetDefaults 设置默认配置值
func (c *Config) SetDefaults() {
	if c.MaxSize == 0 {
		c.MaxSize = 100 * 1024 * 1024 // 默认100MB
	}
	if c.MaxDays == 0 {
		c.MaxDays = 7 // 默认保存7天
	}
	if c.AsyncBuffer == 0 && c.Async {
		c.AsyncBuffer = 1000 // 默认异步缓冲1000条
	}
	if c.Prefix == "" {
		c.Prefix = "app" // 默认前缀
	}
}

// 定义函数类型，方便赋值
type logFunc func(args ...interface{})

// logEntry 内部日志条目（仅用于异步模式）
// 保存了日志等级、参数构建后的消息缓冲区
// 注意：这里传递 *bytes.Buffer 给后台协程使用，确保不会在发送后立即归还到对象池
// 由后台协程在写入完成后负责 PutBuffer// logEntry 异步日志条目 - 优化版本，减少内存分配
type logEntry struct {
	level Level
	msg   string    // 直接存储字符串，避免Buffer的额外分配
	ts    time.Time // 固定记录时间（按用户要求传入下一步）
}

// LoggerImpl 日志实现
// LoggerImpl 是日志器的具体实现，支持同步与异步写入、采样和结构化字段
type LoggerImpl struct {
	config *Config
	mutex  sync.RWMutex // 用于保护文件句柄与轮转

	trace logFunc // 跟踪日志
	debug logFunc // 调试日志
	info  logFunc // 信息日志
	warn  logFunc // 警告日志
	error logFunc // 错误日志
	fatal logFunc // 致命错误日志
	panic logFunc // 恐慌日志

	file        *os.File // 当前日志文件
	currentSize int64    // 当前文件大小
	currentDay  string   // 当前日期

	// 采样计数器（全局原子计数）
	sampleCounter uint64

	// 异步写入相关
	asyncChan chan *logEntry
	wg        sync.WaitGroup
}

// NewLogger 创建新的日志器
func NewLogger(config *Config) (ILogger, error) {
	// 设置默认值
	config.SetDefaults()

	// 验证配置
	if err := config.Validate(); err != nil {
		return nil, fmt.Errorf("配置验证失败: %v", err)
	}

	l := &LoggerImpl{
		config: config,
	}

	// 如果配置了文件输出，初始化文件
	if config.Output != "" {
		if err := l.initFileOutput(); err != nil {
			return nil, fmt.Errorf("初始化文件输出失败: %v", err)
		}
	}

	// 根据日志级别初始化对应日志函数
	l.initLogFunctions()

	// 启动清理协程
	go l.cleanupRoutine()

	// 如果启用异步写入，启动后台写入协程
	if l.config.Async {
		// 默认缓冲区
		bufSize := l.config.AsyncBuffer
		if bufSize <= 0 {
			bufSize = 1024
		}
		l.asyncChan = make(chan *logEntry, bufSize)
		l.wg.Add(1)
		go l.asyncWorker()
	}

	return l, nil
}

// initFileOutput 初始化文件输出
func (l *LoggerImpl) initFileOutput() error {
	// 确保目录存在
	if err := os.MkdirAll(l.config.Output, 0755); err != nil {
		return fmt.Errorf("创建目录失败: %v", err)
	}

	// 生成带时间戳的文件名：前缀-时间戳.log
	now := time.Now()
	l.currentDay = now.Format("2006-01-02")
	timestamp := now.Format("2006-01-02-15-04-05")

	// 避免fmt.Sprintf的内存分配
	buf := GetBuffer()
	WriteString(buf, l.config.Prefix)
	buf.WriteByte('-')
	WriteString(buf, timestamp)
	WriteString(buf, ".log")
	filename := buf.String()
	PutBuffer(buf)
	filePath := filepath.Join(l.config.Output, filename)

	// 打开文件
	file, err := os.OpenFile(filePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	if err != nil {
		return fmt.Errorf("打开日志文件失败: %v", err)
	}

	// 获取文件大小
	stat, err := file.Stat()
	if err != nil {
		file.Close()
		return fmt.Errorf("获取文件信息失败: %v", err)
	}

	l.file = file
	l.currentSize = stat.Size()

	return nil
}

// initLogFunctions 初始化日志函数
func (l *LoggerImpl) initLogFunctions() {
	if l.config.Level <= TraceLevel {
		l.trace = l.realTrace
	} else {
		l.trace = l.noop
	}

	if l.config.Level <= DebugLevel {
		l.debug = l.realDebug
	} else {
		l.debug = l.noop
	}

	if l.config.Level <= InfoLevel {
		l.info = l.realInfo
	} else {
		l.info = l.noop
	}

	if l.config.Level <= WarnLevel {
		l.warn = l.realWarn
	} else {
		l.warn = l.noop
	}

	if l.config.Level <= ErrorLevel {
		l.error = l.realError
	} else {
		l.error = l.noop
	}

	if l.config.Level <= FatalLevel {
		l.fatal = l.realFatal
	} else {
		l.fatal = l.noop
	}

	if l.config.Level <= PanicLevel {
		l.panic = l.realPanic
	} else {
		l.panic = l.noop
	}
}

// 空实现，什么都不做
func (l *LoggerImpl) noop(args ...interface{}) {}

// 真实日志打印实现
func (l *LoggerImpl) realTrace(args ...interface{}) { l.writeLog(TraceLevel, args...) }
func (l *LoggerImpl) realDebug(args ...interface{}) { l.writeLog(DebugLevel, args...) }
func (l *LoggerImpl) realInfo(args ...interface{})  { l.writeLog(InfoLevel, args...) }
func (l *LoggerImpl) realWarn(args ...interface{})  { l.writeLog(WarnLevel, args...) }
func (l *LoggerImpl) realError(args ...interface{}) { l.writeLog(ErrorLevel, args...) }
func (l *LoggerImpl) realFatal(args ...interface{}) {
	l.writeLog(FatalLevel, args...)
	os.Exit(1)
}
func (l *LoggerImpl) realPanic(args ...interface{}) {
	l.writeLog(PanicLevel, args...)
	panic(fmt.Sprint(args...))
}

// ---------- 结构化日志方法实现 ----------

// TraceWithFields 带字段的跟踪日志
func (l *LoggerImpl) TraceWithFields(msg string, fields Fields) {
	if l.config.Level <= TraceLevel {
		l.writeLogWithFields(TraceLevel, msg, fields)
	}
}

// DebugWithFields 带字段的调试日志
func (l *LoggerImpl) DebugWithFields(msg string, fields Fields) {
	if l.config.Level <= DebugLevel {
		l.writeLogWithFields(DebugLevel, msg, fields)
	}
}

// InfoWithFields 带字段的信息日志
func (l *LoggerImpl) InfoWithFields(msg string, fields Fields) {
	if l.config.Level <= InfoLevel {
		l.writeLogWithFields(InfoLevel, msg, fields)
	}
}

// WarnWithFields 带字段的警告日志
func (l *LoggerImpl) WarnWithFields(msg string, fields Fields) {
	if l.config.Level <= WarnLevel {
		l.writeLogWithFields(WarnLevel, msg, fields)
	}
}

// ErrorWithFields 带字段的错误日志
func (l *LoggerImpl) ErrorWithFields(msg string, fields Fields) {
	if l.config.Level <= ErrorLevel {
		l.writeLogWithFields(ErrorLevel, msg, fields)
	}
}

// writeLogWithFields 专门处理结构化日志的内部方法
func (l *LoggerImpl) writeLogWithFields(level Level, msg string, fields Fields) {
	// 采样检查
	if l.config.SampleEvery > 1 {
		c := atomic.AddUint64(&l.sampleCounter, 1)
		if int(c%uint64(l.config.SampleEvery)) != 0 {
			return
		}
	}

	// 使用缓存池构建日志消息
	buf := GetBuffer()

	// 写入消息
	WriteString(buf, msg)

	// 写入默认字段
	if l.config.DefaultFields != nil && len(l.config.DefaultFields) > 0 {
		buf.WriteByte(' ')
		l.writeFieldsToBuffer(buf, l.config.DefaultFields)
	}

	// 写入传入的字段
	if fields != nil && len(fields) > 0 {
		buf.WriteByte(' ')
		l.writeFieldsToBuffer(buf, fields)
	}

	// 处理输出
	l.processLogOutput(level, buf)
}

// processLogOutput 处理日志输出的通用方法 - 零分配优化版本
func (l *LoggerImpl) processLogOutput(level Level, buf *bytes.Buffer) {
	ts := time.Now()
	
	if l.config.Async {
		// 异步模式：需要复制字符串
		msgStr := buf.String()
		PutBuffer(buf)
		
		entry := &logEntry{
			level: level,
			msg:   msgStr,
			ts:    ts,
		}
		select {
		case l.asyncChan <- entry:
		default:
			fmt.Fprintf(os.Stderr, "警告：日志队列已满，丢弃日志: %s\n", msgStr)
		}
	} else {
		// 同步模式：零分配优化
		l.writeLogDirect(level, buf, ts)
		PutBuffer(buf)
	}
}

// writeLog 内部统一调用写日志的方法 - 优化版本，减少内存分配
func (l *LoggerImpl) writeLog(level Level, args ...interface{}) {
	// 采样检查：在最前面进行，尽早返回
	if l.config.SampleEvery > 1 {
		c := atomic.AddUint64(&l.sampleCounter, 1)
		if int(c%uint64(l.config.SampleEvery)) != 0 {
			return
		}
	}

	// 使用缓存池构建日志消息
	buf := GetBuffer()

	// 写入默认字段
	if l.config.DefaultFields != nil && len(l.config.DefaultFields) > 0 {
		l.writeFieldsToBuffer(buf, l.config.DefaultFields)
		if len(args) > 0 {
			buf.WriteByte(' ')
		}
	}

	// 构建消息内容
	l.writeArgsToBuffer(buf, args...)

	// 处理输出
	l.processLogOutput(level, buf)
}

// writeArgsToBuffer 将任意参数写入缓冲区（优化版本）
func (l *LoggerImpl) writeArgsToBuffer(buf *bytes.Buffer, args ...interface{}) {
	for i, arg := range args {
		if i > 0 {
			buf.WriteByte(' ')
		}

		switch v := arg.(type) {
		case Field:
			WriteString(buf, v.Key)
			buf.WriteByte('=')
			l.writeValue(buf, v.Value)
		case Fields:
			l.writeFieldsToBuffer(buf, v)
		case map[string]interface{}:
			l.writeFieldsToBuffer(buf, Fields(v))
		case string:
			WriteString(buf, v)
		case int:
			WriteInt(buf, v)
		case int64:
			WriteInt(buf, int(v))
		case int32:
			WriteInt(buf, int(v))
		case int16:
			WriteInt(buf, int(v))
		case int8:
			WriteInt(buf, int(v))
		case uint:
			WriteInt(buf, int(v))
		case uint64:
			WriteInt(buf, int(v))
		case uint32:
			WriteInt(buf, int(v))
		case uint16:
			WriteInt(buf, int(v))
		case uint8:
			WriteInt(buf, int(v))
		case float64:
			WriteFloat(buf, v, 2)
		case float32:
			WriteFloat(buf, float64(v), 2)
		case bool:
			WriteBool(buf, v)
		case nil:
			WriteString(buf, "<nil>")
		default:
			// 使用反射避免fmt.Sprintf的内存分配
			l.writeValueReflect(buf, v)
		}
	}
}

// writeValue 写入单个值（优化版本）
func (l *LoggerImpl) writeValue(buf *bytes.Buffer, v interface{}) {
	switch x := v.(type) {
	case string:
		WriteString(buf, x)
	case int:
		WriteInt(buf, x)
	case int64:
		WriteInt(buf, int(x))
	case int32:
		WriteInt(buf, int(x))
	case int16:
		WriteInt(buf, int(x))
	case int8:
		WriteInt(buf, int(x))
	case uint:
		WriteInt(buf, int(x))
	case uint64:
		WriteInt(buf, int(x))
	case uint32:
		WriteInt(buf, int(x))
	case uint16:
		WriteInt(buf, int(x))
	case uint8:
		WriteInt(buf, int(x))
	case float64:
		WriteFloat(buf, x, 2)
	case float32:
		WriteFloat(buf, float64(x), 2)
	case bool:
		WriteBool(buf, x)
	case nil:
		WriteString(buf, "<nil>")
	default:
		// 使用反射避免fmt.Sprintf的内存分配
		l.writeValueReflect(buf, v)
	}
}

// writeFieldsToBuffer 将 Fields 写入缓冲区（优化版本）
func (l *LoggerImpl) writeFieldsToBuffer(buf *bytes.Buffer, f Fields) {
	first := true
	for k, v := range f {
		if !first {
			buf.WriteByte(' ')
		}
		WriteString(buf, k)
		buf.WriteByte('=')
		l.writeValue(buf, v)
		first = false
	}
}

// writeValueReflect 使用反射写入任意类型值，避免fmt.Sprintf的内存分配
func (l *LoggerImpl) writeValueReflect(buf *bytes.Buffer, v interface{}) {
	switch x := v.(type) {
	case error:
		WriteString(buf, x.Error())
	case []byte:
		buf.Write(x)
	case fmt.Stringer:
		WriteString(buf, x.String())
	default:
		// 对于其他类型，使用类型断言处理常见情况
		if s, ok := v.(string); ok {
			WriteString(buf, s)
		} else {
			// 最后才使用fmt包，但尽量避免
			WriteString(buf, fmt.Sprintf("%v", v))
		}
	}
}

// asyncWorker 异步写入后台协程 - 优化版本
// 负责：格式化日志、检查轮转、输出到文件与控制台
func (l *LoggerImpl) asyncWorker() {
	defer l.wg.Done()
	for entry := range l.asyncChan {
		// 直接使用字符串，无需转换
		msg := entry.msg
		if len(msg) > 0 && msg[len(msg)-1] == '\n' {
			msg = msg[:len(msg)-1]
		}

		// 使用记录时刻的时间戳
		fileLine := FormatFileLineAt(entry.level, msg, entry.ts, l.config.EnableSource)
		consoleLine := FormatConsoleLineAt(entry.level, msg, entry.ts, l.config.EnableSource)

		// 分别调用两个writer，内部各自加锁
		l.writeFileLine(fileLine)
		l.writeConsoleLine(consoleLine)

		// 无需归还缓冲区，因为已经改为字符串
	}
}

// writeFileLine 写入到文件（内部加锁并处理轮转）
func (l *LoggerImpl) writeFileLine(line string) {
	if l.file == nil || line == "" {
		return
	}
	l.mutex.Lock()
	defer l.mutex.Unlock()
	// 检查是否需要轮转文件
	l.checkRotation()
	if l.file != nil {
		n, _ := l.file.WriteString(line)
		l.currentSize += int64(n)
	}
}

// writeLogDirect 零分配直接写入方法
func (l *LoggerImpl) writeLogDirect(level Level, msgBuf *bytes.Buffer, ts time.Time) {
	// 获取格式化器
	formatter := globalFormatter
	
	// 文件输出
	if l.config.Output != "" {
		fileBuf := formatter.bufferPool.Get()
		defer formatter.bufferPool.Put(fileBuf)
		
		// 直接格式化到buffer
		formatter.FormatDirectToBuffer(fileBuf, level, ts, l.config.EnableSource, false)
		// 在时间戳和等级之间插入消息内容
		l.insertMessageContent(fileBuf, msgBuf)
		
		l.writeFileBuffer(fileBuf)
	}
	
	// 控制台输出
	if l.config.EnableConsole {
		consoleBuf := formatter.bufferPool.Get()
		defer formatter.bufferPool.Put(consoleBuf)
		
		// 直接格式化到buffer
		formatter.FormatDirectToBuffer(consoleBuf, level, ts, l.config.EnableSource, true)
		// 在时间戳和等级之间插入消息内容
		l.insertMessageContent(consoleBuf, msgBuf)
		
		l.writeConsoleBuffer(consoleBuf)
	}
}

// insertMessageContent 在格式化的buffer中插入消息内容
func (l *LoggerImpl) insertMessageContent(destBuf *bytes.Buffer, msgBuf *bytes.Buffer) {
	// 找到"| "的位置，在其后插入消息内容
	content := destBuf.Bytes()
	pipePos := bytes.LastIndex(content, []byte("| "))
	if pipePos != -1 {
		// 在"| "后插入消息和空格
		insertPos := pipePos + 2
		// 重新构建buffer内容
		newContent := make([]byte, 0, len(content)+msgBuf.Len())
		newContent = append(newContent, content[:insertPos]...)
		newContent = append(newContent, msgBuf.Bytes()...)
		newContent = append(newContent, content[insertPos:]...)
		
		destBuf.Reset()
		destBuf.Write(newContent)
	}
}

// writeFileBuffer 写入文件buffer
func (l *LoggerImpl) writeFileBuffer(buf *bytes.Buffer) {
	if l.file == nil || buf.Len() == 0 {
		return
	}
	l.mutex.Lock()
	defer l.mutex.Unlock()
	// 检查是否需要轮转文件
	l.checkRotation()
	if l.file != nil {
		n, _ := l.file.Write(buf.Bytes())
		l.currentSize += int64(n)
	}
}

// writeConsoleBuffer 写入控制台buffer
func (l *LoggerImpl) writeConsoleBuffer(buf *bytes.Buffer) {
	if !l.config.EnableConsole || buf.Len() == 0 {
		return
	}
	l.mutex.Lock()
	defer l.mutex.Unlock()
	os.Stdout.Write(buf.Bytes())
}

// writeConsoleLine 写入到控制台（内部加锁，保持与文件输出时序一致）
func (l *LoggerImpl) writeConsoleLine(line string) {
	if !l.config.EnableConsole || line == "" {
		return
	}
	l.mutex.Lock()
	defer l.mutex.Unlock()
	fmt.Print(line)
}

// checkRotation 检查是否需要文件轮转
func (l *LoggerImpl) checkRotation() {
	if l.file == nil {
		return
	}

	// 检查文件大小
	if l.config.MaxSize > 0 && l.currentSize >= l.config.MaxSize {
		l.rotateFile()
		return
	}

	// 检查日期变化
	currentDay := time.Now().Format("2006-01-02")
	if l.currentDay != currentDay {
		l.rotateFile()
	}
}

// rotateFile 轮转文件
func (l *LoggerImpl) rotateFile() {
	// 关闭当前文件
	if l.file != nil {
		l.file.Close()
		l.file = nil
	}

	// 重新初始化文件输出
	l.initFileOutput()
}

// cleanupRoutine 清理过期文件的协程
func (l *LoggerImpl) cleanupRoutine() {
	if l.config.MaxDays <= 0 {
		return
	}

	ticker := time.NewTicker(24 * time.Hour) // 每天检查一次
	defer ticker.Stop()

	for range ticker.C {
		l.cleanupOldFiles()
	}
}

// cleanupOldFiles 清理过期文件
func (l *LoggerImpl) cleanupOldFiles() {
	if l.config.Output == "" || l.config.MaxDays <= 0 {
		return
	}

	cutoffTime := time.Now().AddDate(0, 0, -l.config.MaxDays)

	filepath.Walk(l.config.Output, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return nil
		}

		// 只处理日志文件
		if !strings.HasPrefix(info.Name(), l.config.Prefix+"-") || !strings.HasSuffix(info.Name(), ".log") {
			return nil
		}

		// 检查文件修改时间
		if info.ModTime().Before(cutoffTime) {
			os.Remove(path)
		}

		return nil
	})
}

// Close 关闭日志器
func (l *LoggerImpl) Close() error {
	// 先关闭异步通道并等待后台协程退出
	if l.config.Async && l.asyncChan != nil {
		close(l.asyncChan)
		l.wg.Wait()
	}

	l.mutex.Lock()
	defer l.mutex.Unlock()

	if l.file != nil {
		err := l.file.Close()
		l.file = nil
		return err
	}
	return nil
}

// 导出的接口方法

// Trace 跟踪日志
func (l *LoggerImpl) Trace(args ...interface{}) { l.trace(args...) }

// Debug 调试日志
func (l *LoggerImpl) Debug(args ...interface{}) { l.debug(args...) }

// Info 信息日志
func (l *LoggerImpl) Info(args ...interface{}) { l.info(args...) }

// Warn 警告日志
func (l *LoggerImpl) Warn(args ...interface{}) { l.warn(args...) }

// Error 错误日志
func (l *LoggerImpl) Error(args ...interface{}) { l.error(args...) }

// Fatal 致命错误日志（调用后进程将退出）
func (l *LoggerImpl) Fatal(args ...interface{}) { l.fatal(args...) }

// Panic 恐慌日志（调用后触发panic）
func (l *LoggerImpl) Panic(args ...interface{}) { l.panic(args...) }
